package netty.time;

/**
 * @Description: 对TCP字节流传输数据，会存在一个逻辑单元不同时到达的问题，该类演示第一种解决方案
 * The simplistic solution is to create an internal cumulative buffer and wait until all 4 bytes are received into the
 * internal buffer. The following is the modified TimeClientHandler implementation that fixes the problem:
 * @Author: zhongyuan
 * @CreateDate: 2020/8/25
 * @Version: OSINT1.1
 */
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

public class TimeClientHandler2 extends ChannelInboundHandlerAdapter {
    private ByteBuf buf;

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        /**
         * 1) A ChannelHandler has two life cycle listener methods: handlerAdded() and handlerRemoved(). You can perform an
         * arbitrary (de)initialization task as long as it does not block for a long time.
         */
        buf = ctx.alloc().buffer(4);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        buf.release(); // (1)
        buf = null;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf m = (ByteBuf) msg;
        /*
        2)First, all received data should be cumulated into buf.
         */
        buf.writeBytes(m);
        m.release();

        /**
         * And then, the handler must check if buf has enough data, 4 bytes in this example, and proceed to the actual
         * business logic. Otherwise, Netty will call the channelRead() method again when more data arrives, and eventually
         * all 4 bytes will be cumulated.
         */
        if (buf.readableBytes() >= 4) { // (3)
            long currentTimeMillis = (buf.readUnsignedInt() - 2208988800L) * 1000L;
            System.out.println(new Date(currentTimeMillis));
            ctx.close();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}